package socketinterface;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.BufferedInputStream;

import java.net.ServerSocket;
import java.net.Socket;

import jp.kentaro.plugin.memoryimageview.views.ViewPart;


public class ServerController implements Runnable {
	public  ViewPart     view;
	private int          serverPort   = 20000;
	private ServerSocket serverSocket = null;
	private Socket clientSocket = null;
	private Logger       logger;
	public final byte PK_MEMORY_UPDATE = 10;
	public final byte PK_MEMORY_PAUSE  = 11;
	public final byte PK_MEMORY_RESUME = 12;
	public final byte PK_MEMORY_ADD    = 13;
	public final byte PK_MEMORY_REMOVE = 14;
	
	public ServerController(ViewPart view){
		this.view = view;
		logger = new TextBoxLogger(view.display, view.consoleBox);
	}

	public void setPortNumber(int portNumber) {
		this.serverPort = portNumber;
	}
	
	public void createServerSocket() {
		try {
			logger.writeEntry("Create Server Socket");
			logger.writeEntry("Port Number: " + serverPort);
			serverSocket = new ServerSocket(serverPort);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void stopListening(){
		
	}
	
	public void startServer() {
		createServerSocket();
		new Thread(this).start();
	}
	
	
	public static String fromByteToHexString(byte b) {
		int i = (byte)b;
		if (i < 0) { i += 256; }
		return Integer.toHexString((int)i);
	}
	
	public void receivePacket(Socket clientSocket) throws IOException {
		DataInputStream in = null;
		in = new DataInputStream(clientSocket.getInputStream());
		
		while(true) {
			short  sizeOfPacket = in.readShort();
			byte   command      = in.readByte();
			logger.writeEntry("Received " + sizeOfPacket + "bytes Data");
			
			switch (command) {
				case MemoryImageProtocol.PK_MEMORY_UPDATE : logger.writeEntry("PK_MEMORY_UPDATE"); break;
				case MemoryImageProtocol.PK_MEMORY_PAUSE  : logger.writeEntry("PK_MEMORY_PAUSE"); break;
				case MemoryImageProtocol.PK_MEMORY_RESUME : logger.writeEntry("PK_MEMORY_RESUME"); break;
				case MemoryImageProtocol.PK_MEMORY_ADD    : logger.writeEntry("PK_MEMORY_ADD"); break;
				case MemoryImageProtocol.PK_MEMORY_REMOVE : logger.writeEntry("PK_MEMORY_REMOVE"); break;
				default : logger.writeEntry("Unknown command :" + command); return;
			}
		
			if (sizeOfPacket > 3) {
				int remainedByte = sizeOfPacket-3;
				logger.writeEntry("Remained Byte: " + remainedByte);
				byte[] packetBody = new byte[remainedByte];
				int recievedBytes = 0;
				while(recievedBytes != remainedByte) {
					recievedBytes += in.read(packetBody);
				}
				logger.writeEntry("Recieved Byte: " + recievedBytes);
				int index = 0;
				for (byte data : packetBody) {
					logger.writeEntry("# " + index + ": 0x" + fromByteToHexString(data));
					index ++;
				}
			}
			
			short endMarker = in.readShort();
			if (endMarker != 32767) {
				logger.writeEntry("EndMarker is broken. : EndMarker = 0x" + Integer.toHexString((int)endMarker) + " (" + Integer.toString((int)endMarker) + ")");
			}
		}		
	}
	
	public void run() {
		// TODO Auto-generated method stub
		
		try {
			logger.writeEntry("Waiting for client connection");
			clientSocket = serverSocket.accept();
			logger.writeEntry("Handing client at" + clientSocket.getInetAddress().getHostName() + " on port " + clientSocket.getPort());		
		} catch (IOException e) {
			logger.writeEntry("Connection Error");
			
		}
		while (true){
		try {
			receivePacket(clientSocket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
	}
}
